

import pandas as pd
import json
import re
import os
from pathlib import Path
from typing import List, Dict, Optional, Union


def extract_architecture_info(text: Optional[str]) -> Dict[str, Optional[Union[str, float, int]]]:
    """
    从建筑描述文本中提取关键信息
    
    参数:
        text: 建筑描述文本

    返回:
        包含年份、面积、规模、保存状态、详细位置的字典
    """
    if pd.isna(text) or not isinstance(text, str):
        return {
            'year': None,
            'area': None,
            'scale': None,
            'status': None,
            'location_detail': None
        }
    
    result = {
        'year': None,
        'area': None,
        'scale': None,
        'status': None,
        'location_detail': None
    }
    
    # 1. 提取年份信息
    year_patterns = [
        r'(\d{3,4})\s*年',          # 直接年份，如1234年
        r'公元\s*(\d{3,4})',        # 公元年份
        r'(\d{1,2})\s*世纪',        # 世纪，如12世纪
        r'(\d{1,2})\s*世纪\s*(\d{1,2})\s*年代'  # 世纪年代，如12世纪30年代
    ]
    
    for pattern in year_patterns:
        match = re.search(pattern, text)
        if match:
            try:
                if '世纪' in pattern:
                    if len(match.groups()) == 2:
                        # 世纪年代格式
                        century = int(match.group(1))
                        decade = int(match.group(2))
                        result['year'] = f"{century}世纪{decade}年代"
                    else:
                        # 仅世纪
                        century = int(match.group(1))
                        result['year'] = f"{century}世纪"
                else:
                    # 具体年份
                    year = int(match.group(1))
                    # 处理可能的年份异常值（合理范围：公元前2000年到1949年）
                    if year > 1949 or year < -2000:
                        continue
                    result['year'] = year
                break
            except (ValueError, IndexError):
                continue
    
    # 2. 提取面积信息（统一转换为平方米）
    area_patterns = [
        r'(\d+(?:\.\d+)?)\s*平方(?:千米|公里)',  # 平方千米/公里
        r'(\d+(?:\.\d+)?)\s*公顷',              # 公顷
        r'(\d+(?:\.\d+)?)\s*亩',                # 亩
        r'(\d+(?:\.\d+)?)\s*平方米',            # 平方米
        r'(\d+(?:\.\d+)?)\s*万\s*平方米'        # 万平方米
    ]
    
    # 面积转换系数（转换为平方米）
    area_converters = {
        '平方(?:千米|公里)': 1000000,
        '公顷': 10000,
        '亩': 666.67,
        '平方米': 1,
        '万\s*平方米': 10000
    }
    
    for pattern in area_patterns:
        match = re.search(pattern, text)
        if match:
            try:
                area_value = float(match.group(1))
                # 确定转换系数并计算
                for unit, factor in area_converters.items():
                    if re.search(unit, pattern):
                        converted_area = round(area_value * factor, 2)
                        result['area'] = converted_area
                        break
                break
            except (ValueError, IndexError):
                continue
    
    # 3. 提取规模描述
    scale_keywords = {
        '宏伟': '宏伟',
        '宏大': '宏大',
        '巨大': '巨大',
        '壮丽': '壮丽',
        '小型': '小型',
        '中型': '中型',
        '大型': '大型',
        '规模庞大': '规模庞大',
        '规模较小': '规模较小',
        '占地面积广阔': '占地面积广阔',
        '气势恢宏': '气势恢宏',
        '小巧玲珑': '小巧玲珑'
    }
    
    for keyword, scale_desc in scale_keywords.items():
        if keyword in text:
            result['scale'] = scale_desc
            break
    
    # 4. 提取现存状态
    status_patterns = [
        (r'今已不存|现已不存|已毁|已不存在|不复存在|毁于', '已损毁/不存'),
        (r'现存|至今仍存|保存完好|保存完整|完好保存', '现存完好'),
        (r'部分保存|部分现存|部分完好', '部分保存'),
        (r'重建|重修|复建|新建', '重建/重修'),
        (r'遗址|遗迹|残存|残址', '仅存遗址'),
        (r'修缮|修复', '已修缮')
    ]
    
    for pattern, status in status_patterns:
        if re.search(pattern, text):
            result['status'] = status
            break
    
    # 5. 提取详细位置信息
    location_patterns = [
        r'位于(.*?)[，。；！？]',
        r'在(.*?)[，。；！？]',
        r'地处(.*?)[，。；！？]',
        r'坐落于(.*?)[，。；！？]'
    ]
    
    for pattern in location_patterns:
        match = re.search(pattern, text)
        if match and len(match.group(1)) < 50:  # 限制长度，避免提取过长文本
            location_detail = match.group(1).strip()
            # 过滤无效位置信息
            if not any(keyword in location_detail for keyword in ['描述', '记载', '详见', '参见']):
                result['location_detail'] = location_detail
            break
    
    return result


def validate_excel_columns(df: pd.DataFrame) -> bool:
    """
    验证Excel文件是否包含必要的列
    
    参数:
        df: 读取的Excel DataFrame
        
    返回:
        包含必要列返回True，否则返回False
    """
    required_columns = ['时期', '建筑名称', '建筑类别', '城市建筑总体描述', '出处']
    return all(col in df.columns for col in required_columns)


def extract_architecture_data_from_excel(file_path: str) -> List[Dict]:
    """
    从建筑Excel文件中提取数据，处理所有sheet
    
    参数:
        file_path: Excel文件路径
        
    返回:
        包含所有建筑数据的列表
    """
    try:
        # 验证文件是否存在
        if not os.path.exists(file_path):
            print(f"错误: 文件不存在 - {file_path}")
            return []
        
        # 读取Excel文件的所有sheet
        excel_file = pd.ExcelFile(file_path)
        all_results = []
        
        print(f"开始处理Excel文件: {os.path.basename(file_path)}")
        print(f"文件共包含 {len(excel_file.sheet_names)} 个sheet")
        
        for sheet_name in excel_file.sheet_names:
            print(f"\n正在处理sheet: {sheet_name}")
            
            try:
                # 读取当前sheet
                df = pd.read_excel(file_path, sheet_name=sheet_name)
                
                # 验证列名
                if not validate_excel_columns(df):
                    print(f"警告: sheet '{sheet_name}' 列名不完整，跳过该sheet")
                    print(f"当前sheet列名: {df.columns.tolist()}")
                    print(f"要求列名: ['时期', '建筑名称', '建筑类别', '城市建筑总体描述', '出处']")
                    continue
                
                # 处理每一行数据
                sheet_records = 0
                for idx, row in df.iterrows():
                    # 提取基础信息，处理空值
                    period = str(row['时期']) if not pd.isna(row['时期']) else None
                    name = str(row['建筑名称']) if not pd.isna(row['建筑名称']) else None
                    category = str(row['建筑类别']) if not pd.isna(row['建筑类别']) else None
                    description = str(row['城市建筑总体描述']) if not pd.isna(row['城市建筑总体描述']) else None
                    source = str(row['出处']) if not pd.isna(row['出处']) else None
                    
                    # 至少需要时期和建筑名称
                    if not period or not name:
                        continue
                    
                    # 从描述中提取详细信息
                    extracted_info = extract_architecture_info(description)
                    
                    # 创建数据记录
                    record = {
                        'sheet_name': sheet_name,
                        'period': period,  # 时期/朝代
                        'architecture_name': name,  # 建筑名称
                        'architecture_category': category,  # 建筑类别
                        'year': extracted_info['year'],  # 年份/年代
                        'area_sqm': extracted_info['area'],  # 面积（平方米）
                        'scale': extracted_info['scale'],  # 规模描述
                        'preservation_status': extracted_info['status'],  # 保存状态
                        'location_detail': extracted_info['location_detail'],  # 详细位置
                        'description': description,  # 原始描述
                        'source': source,  # 出处
                        'record_index': idx + 1  # 记录在sheet中的行号（从1开始）
                    }
                    
                    # 添加到结果列表
                    all_results.append(record)
                    sheet_records += 1
                
                print(f"sheet '{sheet_name}' 处理完成，提取 {sheet_records} 条记录")
            
            except Exception as sheet_error:
                print(f"处理sheet '{sheet_name}' 时出错: {str(sheet_error)}")
                continue
        
        print(f"\n所有sheet处理完成，共提取 {len(all_results)} 条建筑数据记录")
        return all_results
    
    except Exception as e:
        print(f"读取Excel文件时出错: {str(e)}")
        return []


def save_architecture_data_to_json(data: List[Dict], output_file: str) -> bool:
    """
    将建筑数据保存为JSON文件
    
    参数:
        data: 建筑数据列表
        output_file: 输出JSON文件路径
        
    返回:
        保存成功返回True，否则返回False
    """
    try:
        # 创建输出目录
        output_dir = os.path.dirname(output_file)
        if output_dir and not os.path.exists(output_dir):
            os.makedirs(output_dir, exist_ok=True)
            print(f"创建输出目录: {output_dir}")
        
        # 保存为JSON文件（确保中文正常显示）
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        print(f"数据已成功保存到: {output_file}")
        print(f"文件大小: {os.path.getsize(output_file) / 1024:.2f} KB")
        return True
    
    except Exception as e:
        print(f"保存JSON文件时出错: {str(e)}")
        return False


def analyze_architecture_data(data: List[Dict]) -> Dict:
    """
    分析建筑数据的基本统计信息
    
    参数:
        data: 建筑数据列表
        
    返回:
        包含统计信息的字典
    """
    if not data:
        print("没有数据可分析")
        return {}
    
    print("\n" + "=" * 60)
    print("=== 建筑数据统计分析报告 ===")
    print("=" * 60)
    
    # 转换为DataFrame以便分析
    df_analysis = pd.DataFrame(data)
    
    # 1. 时期分布统计
    print("\n1. 各时期建筑数量分布:")
    period_counts = df_analysis['period'].value_counts()
    for period, count in period_counts.items():
        percentage = (count / len(data)) * 100
        print(f"   {period:10s}: {count:4d} 座 ({percentage:5.1f}%)")
    
    # 2. 建筑类别分布
    print("\n2. 建筑类别分布:")
    category_counts = df_analysis['architecture_category'].value_counts()
    for category, count in category_counts.items():
        percentage = (count / len(data)) * 100
        print(f"   {category:10s}: {count:4d} 座 ({percentage:5.1f}%)")
    
    # 3. 保存状态分布
    print("\n3. 建筑保存状态分布:")
    status_counts = df_analysis['preservation_status'].value_counts(dropna=False)
    for status, count in status_counts.items():
        status_display = status if status is not None else "未记录"
        percentage = (count / len(data)) * 100
        print(f"   {status_display:10s}: {count:4d} 座 ({percentage:5.1f}%)")
    
    # 4. 面积数据统计
    print("\n4. 建筑面积统计:")
    area_data = df_analysis['area_sqm'].dropna()
    if len(area_data) > 0:
        print(f"   有面积记录的建筑: {len(area_data)} 座 ({len(area_data)/len(data)*100:.1f}%)")
        print(f"   平均面积: {area_data.mean():10.2f} 平方米")
        print(f"   最大面积: {area_data.max():10.2f} 平方米")
        print(f"   最小面积: {area_data.min():10.2f} 平方米")
        print(f"   面积中位数: {area_data.median():.2f} 平方米")
    else:
        print(f"   没有建筑包含面积记录")
    
    # 5. 年份数据统计
    print("\n5. 建筑年份信息统计:")
    year_data = df_analysis['year'].dropna()
    year_percentage = (len(year_data) / len(data)) * 100
    print(f"   有年份记录的建筑: {len(year_data)} 座 ({year_percentage:.1f}%)")
    
    # 统计具体年份和世纪格式的数量
    specific_years = 0
    century_years = 0
    for year in year_data:
        if isinstance(year, (int, float)):
            specific_years += 1
        elif isinstance(year, str) and '世纪' in year:
            century_years += 1
    
    if len(year_data) > 0:
        print(f"   - 具体年份记录: {specific_years} 座")
        print(f"   - 世纪/年代记录: {century_years} 座")
    
    # 6. 各sheet数据分布
    print("\n6. 各sheet数据分布:")
    sheet_counts = df_analysis['sheet_name'].value_counts()
    for sheet, count in sheet_counts.items():
        percentage = (count / len(data)) * 100
        print(f"   {sheet:15s}: {count:4d} 座 ({percentage:5.1f}%)")
    
    # 7. 数据完整性统计
    print("\n7. 数据字段完整性统计:")
    fields = ['year', 'area_sqm', 'scale', 'preservation_status', 'location_detail']
    for field in fields:
        non_null_count = df_analysis[field].notna().sum()
        completion_rate = (non_null_count / len(data)) * 100
        field_display = {
            'year': '年份信息',
            'area_sqm': '面积信息',
            'scale': '规模描述',
            'preservation_status': '保存状态',
            'location_detail': '详细位置'
        }.get(field, field)
        print(f"   {field_display:8s}: {completion_rate:5.1f}% ({non_null_count}/{len(data)})")
    
    print("=" * 60)
    
    # 返回统计结果
    return {
        'total_records': len(data),
        'period_distribution': period_counts.to_dict(),
        'category_distribution': category_counts.to_dict(),
        'status_distribution': status_counts.to_dict(),
        'area_statistics': {
            'count': len(area_data),
            'mean': area_data.mean() if len(area_data) > 0 else None,
            'max': area_data.max() if len(area_data) > 0 else None,
            'min': area_data.min() if len(area_data) > 0 else None,
            'median': area_data.median() if len(area_data) > 0 else None
        },
        'year_statistics': {
            'total_with_year': len(year_data),
            'specific_years': specific_years,
            'century_years': century_years
        },
        'sheet_distribution': sheet_counts.to_dict(),
        'field_completion': {field: (df_analysis[field].notna().sum() / len(data)) * 100 for field in fields}
    }


def display_sample_records(data: List[Dict], sample_count: int = 5) -> None:
    """
    显示样本数据记录
    
    参数:
        data: 建筑数据列表
        sample_count: 显示的样本数量，默认5
    """
    if not data:
        return
    
    display_count = min(sample_count, len(data))
    print(f"\n=== 前 {display_count} 条数据样本 ===")
    
    for i, record in enumerate(data[:display_count], 1):
        print(f"\n第 {i} 条记录:")
        print(f"   数据来源: {record['sheet_name']} (行 {record['record_index']})")
        print(f"   时期:     {record['period']}")
        print(f"   建筑名称: {record['architecture_name']}")
        print(f"   建筑类别: {record['architecture_category'] or '未分类'}")
        print(f"   年份:     {record['year'] or '未记录'}")
        print(f"   面积:     {f'{record['area_sqm']} 平方米' if record['area_sqm'] is not None else '未记录'}")
        print(f"   规模:     {record['scale'] or '未记录'}")
        print(f"   保存状态: {record['preservation_status'] or '未记录'}")
        print(f"   位置:     {record['location_detail'] or '未记录'}")
        
        # 显示部分来源信息
        if record['source']:
            source_display = record['source'][:100] + "..." if len(record['source']) > 100 else record['source']
            print(f"   来源:     {source_display}")
        
        # 显示部分描述信息
        if record['description']:
            desc_display = record['description'][:150] + "..." if len(record['description']) > 150 else record['description']
            print(f"   描述:     {desc_display}")
        
        print("   " + "-" * 80)


def main(
    input_file: str, 
    output_file: str = 'architecture_data.json',
    sample_count: int = 5
) -> Optional[List[Dict]]:
    """
    主函数：完整的建筑数据处理流程
    
    参数:
        input_file: 输入Excel文件路径
        output_file: 输出JSON文件路径，默认当前目录下的architecture_data.json
        sample_count: 显示的样本数据数量，默认5
        
    返回:
        处理完成的建筑数据列表，失败返回None
    """
    print("=" * 80)
    print("                    其他建筑数据处理工具                    ")
    print("=" * 80)
    
    # 1. 提取数据
    print("\n【步骤1/3】从Excel文件提取建筑数据...")
    architecture_data = extract_architecture_data_from_excel(input_file)
    
    if not architecture_data:
        print("\n错误：未能提取到任何建筑数据，程序终止")
        print("=" * 80)
        return None
    
    # 2. 保存为JSON
    print("\n【步骤2/3】将数据保存为JSON文件...")
    save_success = save_architecture_data_to_json(architecture_data, output_file)
    
    if not save_success:
        print("\n警告：JSON文件保存失败，但数据提取成功")
    else:
        print("\nJSON文件保存成功")
    
    # 3. 数据分析和样本显示
    print("\n【步骤3/3】数据分析和样本展示...")
    analyze_architecture_data(architecture_data)
    display_sample_records(architecture_data, sample_count)
    
    # 完成信息
    print("\n" + "=" * 80)
    print("建筑数据处理完成！")
    print(f"总处理记录数: {len(architecture_data)} 条")
    print(f"输出文件位置: {os.path.abspath(output_file)}")
    print("数据字段说明:")
    print("  - sheet_name: 数据来源sheet名称")
    print("  - period: 建筑所属时期/朝代")
    print("  - architecture_name: 建筑名称")
    print("  - architecture_category: 建筑类别（寺庙、苑囿、行宫等）")
    print("  - year: 建筑相关年份/年代")
    print("  - area_sqm: 建筑面积（单位：平方米）")
    print("  - scale: 建筑规模描述")
    print("  - preservation_status: 建筑保存状态")
    print("  - location_detail: 建筑详细位置信息")
    print("  - description: 建筑原始描述文本")
    print("  - source: 数据来源出处")
    print("  - record_index: 数据在原始sheet中的行号")
    print("=" * 80)
    
    return architecture_data


def main_with_default_paths():
    """
    使用默认路径的主函数，适合快速测试
    """
    # 默认路径配置
    default_input = './data/10其他建筑 - 总数据和各朝代数据.xlsx'  # 输入Excel文件
    default_output = './outputs/other_building_data.json'  # 输出JSON文件
    
    # 检查默认输入文件是否存在
    if os.path.exists(default_input):
        main(default_input, default_output)
    else:
        print(f"默认输入文件不存在: {default_input}")
        print("请使用 main(input_file='你的文件路径.xlsx') 调用函数")


if __name__ == '__main__':
    # 这里可以直接指定文件路径运行
    # 示例：
    # main(input_file='./data/10其他建筑 - 总数据和各朝代数据.xlsx', 
    #      output_file='./output/architecture_data.json',
    #      sample_count=5)
    
    # 默认运行（使用当前目录下的默认文件）
    main_with_default_paths()
